home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
BBS-Archive
/
Comm
/
term-source.lha
/
Extras
/
Source
/
term-Source.lha
/
termARexx.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-07
|
19KB
|
1,056 lines
/*
** termARexx.c
**
** ARexx interface general support routines
**
** Copyright © 1990-1995 by Olaf `Olsen' Barthel
** All Rights Reserved
*/
#include "termARexxGlobal.h"
/* IsNumeric(STRPTR String):
*
* Is the string really a number?
*/
BYTE __regargs
IsNumeric(STRPTR String)
{
while(*String && (*String == ' ' || *String == '\t'))
String++;
while(*String)
{
if(*String < '0' || *String > '9')
return(FALSE);
else
String++;
}
return(TRUE);
}
/* CreateResult(STRPTR ResultString,LONG *Results):
*
* Create a proper Rexx result string.
*/
STRPTR __regargs
CreateResult(STRPTR ResultString,LONG *Results)
{
STRPTR Result;
if(!(Result = CreateArgstring(ResultString,strlen(ResultString))))
{
Results[0] = RC_ERROR;
Results[1] = ERROR_NO_FREE_STORE;
}
return(Result);
}
/* CreateResultLen(STRPTR ResultString,LONG *Results):
*
* Create a proper Rexx result string given the
* length of the source string.
*/
STRPTR __regargs
CreateResultLen(STRPTR ResultString,LONG *Results,LONG Len)
{
STRPTR Result;
if(!(Result = CreateArgstring(ResultString,Len)))
{
Results[0] = RC_ERROR;
Results[1] = ERROR_NO_FREE_STORE;
}
return(Result);
}
/* CreateVarArgs(STRPTR Value,struct RexxPkt *Packet,STRPTR Stem,...):
*
* Set a Rexx variable, special treatment.
*/
BYTE __stdargs
CreateVarArgs(STRPTR Value,struct RexxPkt *Packet,STRPTR Stem,...)
{
UBYTE Name[256];
va_list VarArgs;
LONG Result;
va_start(VarArgs,Stem);
VSPrintf(Name,Stem,VarArgs);
va_end(VarArgs);
if(Result = SetRexxVar(Packet -> RexxMsg,Name,Value,strlen(Value)))
{
Packet -> Results[0] = RC_ERROR;
Packet -> Results[1] = Result;
return(FALSE);
}
else
return(TRUE);
}
/* CreateVar(STRPTR Value,struct RexxPkt *Packet,STRPTR Name):
*
* Set a Rexx variable, simple version.
*/
STRPTR __regargs
CreateVar(STRPTR Value,struct RexxPkt *Packet,STRPTR Name)
{
LONG Result;
if(Result = SetRexxVar(Packet -> RexxMsg,Name,Value,strlen(Value)))
{
Packet -> Results[0] = RC_ERROR;
Packet -> Results[1] = Result;
}
return(NULL);
}
/* CreateMatchBuffer(STRPTR Pattern):
*
* Create a pattern buffer suitable for pattern matching.
*/
STRPTR __regargs
CreateMatchBuffer(STRPTR Pattern)
{
WORD Len = strlen(Pattern) + 1;
STRPTR Buffer;
if(Buffer = (STRPTR)AllocVecPooled(2 * Len,MEMF_ANY))
{
if(ParsePatternNoCase(Pattern,Buffer,2 * Len) != -1)
return(Buffer);
else
FreeVecPooled(Buffer);
}
return(NULL);
}
/* MatchBuffer(STRPTR Buffer,STRPTR Name):
*
* Match a pattern against a string.
*/
BYTE __regargs
MatchBuffer(STRPTR Buffer,STRPTR Name)
{
return((BYTE)MatchPatternNoCase(Buffer,Name));
}
/* DeleteMatchBuffer(STRPTR Buffer):
*
* Free a pattern matching buffer.
*/
VOID __regargs
DeleteMatchBuffer(STRPTR Buffer)
{
FreeVecPooled(Buffer);
}
/* ToMode(STRPTR Name):
*
* Turn a transfer mode name into a key.
*/
WORD __regargs
ToMode(STRPTR Name)
{
STATIC STRPTR TransferModes[] =
{
"BINARY",
"TEXT",
"ASCII",
NULL
};
WORD i;
for(i = 0 ; TransferModes[i] ; i++)
{
if(!Stricmp(Name,TransferModes[i]))
return(i);
}
return(-1);
}
/* ToList(STRPTR Name):
*
* Turn a list name into a key.
*/
WORD __regargs
ToList(STRPTR Name)
{
STATIC STRPTR ListTypes[GLIST_COUNT] =
{
"UPLOAD",
"DOWNLOAD",
"DIAL",
"WAIT",
"TRAP"
};
WORD i;
for(i = 0 ; i < GLIST_COUNT ; i++)
{
if(!Stricmp(Name,ListTypes[i]))
return(i);
}
return(-1);
}
/* ToConfig(STRPTR Name):
*
* Turn a configuration name into a key.
*/
WORD __regargs
ToConfig(STRPTR Name)
{
STATIC STRPTR DataTypes[DATATYPE_COUNT] =
{
"TRANSLATIONS",
"FUNCTIONKEYS",
"CURSORKEYS",
"FASTMACROS",
"HOTKEYS",
"SPEECH",
"SOUND",
"BUFFER",
"CONFIGURATION",
"PHONE",
"SCREENTEXT",
"SCREENIMAGE"
};
WORD i;
for(i = 0 ; i < DATATYPE_COUNT ; i++)
{
if(!Stricmp(Name,DataTypes[i]))
return(i);
}
return(-1);
}
/* ToRequester(STRPTR Name):
*
* Turn a requester name into a key.
*/
WORD __regargs
ToRequester(STRPTR Name)
{
STRPTR RequesterTypes[REQUESTER_COUNT] =
{
"SERIAL",
"MODEM",
"SCREEN",
"TERMINAL",
"EMULATION",
"CLIPBOARD",
"CAPTURE",
"COMMANDS",
"MISC",
"PATH",
"TRANSFER",
"TRANSLATIONS",
"FUNCTIONKEYS",
"CURSORKEYS",
"FASTMACROS",
"HOTKEYS",
"SPEECH",
"SOUND",
"PHONE"
};
WORD i;
for(i = 0 ; i < REQUESTER_COUNT ; i++)
{
if(!Stricmp(Name,RequesterTypes[i]))
return(i);
}
return(-1);
}
/* ToWindow(STRPTR Name):
*
* Turn a window name into a key.
*/
WORD __regargs
ToWindow(STRPTR Name)
{
STATIC STRPTR WindowTypes[WINDOWID_COUNT] =
{
"BUFFER",
"REVIEW",
"PACKET",
"FASTMACROS",
"STATUS",
"MAIN",
"UPLOADQUEUE"
};
WORD i;
for(i = 0 ; i < WINDOWID_COUNT ; i++)
{
if(!Stricmp(WindowTypes[i],Name))
return(i);
}
return(-1);
}
/* ReplyRexxCommand():
*
* Reply a command request the rexx server - or someone else -
* has passed to us.
*/
STATIC VOID __regargs
ReplyRexxCommand(struct RexxMsg *RexxMessage,LONG Primary,LONG Secondary)
{
if(RexxMessage)
{
RexxMessage -> rm_Result1 = Primary;
RexxMessage -> rm_Result2 = Secondary;
ReplyMsg(RexxMessage);
}
}
/* RexxToolServer(VOID):
*
* Asynchronous tool/rexx command execution process.
*/
STATIC VOID __saveds
RexxToolServer(VOID)
{
struct Process *ThisProcess = (struct Process *)SysBase -> ThisTask;
struct RexxPkt *Packet;
BPTR OldCOS,
NewCOS = NULL;
/* Wait for startup packet. */
WaitPort(&ThisProcess -> pr_MsgPort);
Packet = (struct RexxPkt *)GetMsg(&ThisProcess -> pr_MsgPort);
/* Increment usage count. */
ObtainSemaphore(&RexxLaunchSemaphore);
RexxLaunchCount++;
ReleaseSemaphore(&RexxLaunchSemaphore);
/* Create proper output stream if necessary. */
if(!ThisProcess -> pr_COS && ThisProcess -> pr_ConsoleTask)
{
if(NewCOS = Open("*",MODE_NEWFILE))
{
OldCOS = ThisProcess -> pr_COS;
ThisProcess -> pr_COS = NewCOS;
}
}
/* Execute the command. */
(*Packet -> CommandInfo -> Routine)(Packet);
Forbid();
/* Decrement usage count. */
ObtainSemaphore(&RexxLaunchSemaphore);
RexxLaunchCount--;
ReleaseSemaphore(&RexxLaunchSemaphore);
/* Close the output stream. */
if(NewCOS)
{
ThisProcess -> pr_COS = OldCOS;
Close(NewCOS);
}
/* Return the message packet. */
ReplyMsg((struct Message *)Packet);
}
/* InvokeRexxCommand(struct RexxPkt *Packet):
*
* Invoke an ARexx command.
*/
STATIC BYTE __regargs
InvokeRexxCommand(struct RexxPkt *Packet)
{
/* Asynchronous command? */
if(Packet -> CommandInfo -> Async)
{
/* Requires special execution code? */
if(Packet -> CommandInfo -> Tool)
{
struct RexxPkt *NewPacket;
/* Create a command packet. */
if(NewPacket = (struct RexxPkt *)AllocVecPooled(sizeof(struct RexxPkt),MEMF_ANY | MEMF_PUBLIC))
{
enum { ARG_CONSOLE };
struct Process *NewProcess;
BPTR Stream;
/* Set up the command packet. */
CopyMem(Packet,NewPacket,sizeof(struct RexxPkt));
NewPacket -> VanillaMessage . mn_ReplyPort = RexxPort;
NewPacket -> VanillaMessage . mn_Length = sizeof(struct RexxPkt);
/* Create I/O streams. */
if(Packet -> Array[ARG_CONSOLE] && WindowName[0] && Packet -> CommandInfo -> Console)
Stream = Open(WindowName,MODE_NEWFILE);
else
Stream = NULL;
/* Launch the process. */
if(Stream && GoodStream(Stream))
{
struct FileHandle *Handle = (struct FileHandle *)BADDR(Stream);
NewProcess = CreateNewProcTags(
NP_Entry, RexxToolServer,
NP_Input, Stream,
NP_Output, NULL,
NP_ConsoleTask, Handle -> fh_Type,
NP_StackSize, 8000,
NP_Name, "term Rexx Tool Process",
NP_Cli, TRUE,
TAG_DONE);
}
else
{
NewProcess = CreateNewProcTags(
NP_Entry, RexxToolServer,
NP_StackSize, 8000,
NP_ConsoleTask, NULL,
NP_Name, "term Rexx Tool Process",
NP_Cli, TRUE,
TAG_DONE);
}
/* Send the command packet. */
if(NewProcess)
PutMsg(&NewProcess -> pr_MsgPort,(struct Message *)NewPacket);
else
{
FreeVecPooled(NewPacket);
ReplyRexxCommand(Packet -> RexxMsg,-1,0);
if(Stream)
Close(Stream);
}
}
else
ReplyRexxCommand(Packet -> RexxMsg,-1,0);
}
else
{
/* Execute the command on the schedule of the
* rexx server process.
*/
STRPTR Result = (*Packet -> CommandInfo -> Routine)(Packet);
RexxPktCleanup(Packet,Result);
}
}
else
{
struct RexxPkt *NewPacket;
/* Create message packet. */
if(NewPacket = (struct RexxPkt *)AllocVecPooled(sizeof(struct RexxPkt),MEMF_ANY | MEMF_PUBLIC))
{
/* Set up message packet. */
CopyMem(Packet,NewPacket,sizeof(struct RexxPkt));
NewPacket -> VanillaMessage . mn_ReplyPort = RexxPort;
NewPacket -> VanillaMessage . mn_Length = sizeof(struct RexxPkt);
/* Post it. */
PutMsg(TermRexxPort,(struct Message *)NewPacket);
}
else
ReplyRexxCommand(Packet -> RexxMsg,-1,0);
}
return(TRUE);
}
/* ParseRexxCommand(struct RexxMsg *RexxMsg):
*
* Handles the synchronous Rexx commands and returns the
* message if no matching command is found.
*/
STATIC BYTE __regargs
ParseRexxCommand(struct RexxMsg *RexxMsg)
{
UBYTE CommandBuffer[30];
STRPTR Command,
CommandArgs;
LONG Len = 0;
/* Clear the local variables. */
CommandBuffer[0] = 0;
Command = RexxMsg -> rm_Args[0];
CommandArgs = NULL;
/* Skip leading blank spaces. */
while(*Command && (*Command == ' ' || *Command == '\t'))
Command++;
/* Extract the command name. */
do
{
/* Found the end of the string? */
if(!Command[Len])
{
/* Copy the command name. */
strcpy(CommandBuffer,Command);
/* No arguments are provided. */
CommandArgs = NULL;
break;
}
/* Found a blank space? */
if(Command[Len] == ' ' || Command[Len] == '\t')
{
/* Copy the command name. */
memcpy(CommandBuffer,Command,Len);
CommandBuffer[Len] = 0;
/* Look for any arguments. */
CommandArgs = &Command[Len + 1];
/* Skip blank spaces. */
while(*CommandArgs && (*CommandArgs == ' ' || *CommandArgs == '\t'))
CommandArgs++;
break;
}
}
while(++Len < 30);
/* Did we find a command name? */
if(CommandBuffer[0])
{
struct CommandInfo *CommandInfo = NULL;
LONG CommandIndex;
/* Which command is it? */
for(CommandIndex = 0 ; CommandIndex < CommandTableSize ; CommandIndex++)
{
if(!Stricmp(CommandBuffer,CommandTable[CommandIndex] . Name))
{
CommandInfo = &CommandTable[CommandIndex];
break;
}
}
/* Did we find the command? */
if(CommandInfo)
{
struct RexxPkt __aligned Packet;
BYTE Processed = FALSE;
/* Set the result codes to defaults. */
Packet . Results[0] = RC_OK;
Packet . Results[1] = 0;
/* Fill in the rest. */
Packet . CommandInfo = CommandInfo;
Packet . RexxMsg = RexxMsg;
/* Does this command accept any arguments? */
if(CommandInfo -> Arguments)
{
LONG *Array;
/* Determine length of argument string. */
if(CommandArgs)
Len = strlen(CommandArgs);
else
Len = 0;
/* Allocate temporary buffer, we will need to
* attach a line-feed character to the argument
* string.
*/
if(Array = (LONG *)AllocVecPooled(12 * sizeof(LONG) + Len + 2,MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC))
{
STRPTR Buffer;
struct RDArgs *Args;
/* Get the argument buffer. */
Buffer = (STRPTR)&Array[12];
/* Copy the argument string. */
if(CommandArgs && Len)
memcpy(Buffer,CommandArgs,Len);
/* Attach the line-feed character. */
Buffer[Len] = '\n';
/* Allocate argument parser data. */
if(Args = (struct RDArgs *)AllocDosObjectTags(DOS_RDARGS,TAG_DONE))
{
Packet . Array = (STRPTR *)Array;
Packet . Args = Args;
/* Don't prompt for input! */
Args -> RDA_Flags |= RDAF_NOPROMPT;
/* Set up parser data. */
Args -> RDA_Source . CS_Buffer = Buffer;
Args -> RDA_Source . CS_Length = Len + 1;
Args -> RDA_Source . CS_CurChr = 0;
/* Parse the arguments. */
if(ReadArgs(CommandInfo -> Arguments,Array,Args))
{
UWORD Inclusion = InclusionTable[CommandIndex];
BYTE ArgsRequired = FALSE;
WORD i,Counted;
/* Look for required arguments. */
for(i = Counted = 0 ; i < 12 ; i++)
{
if(Inclusion & (1L << i))
{
ArgsRequired = TRUE;
if(Array[i])
Counted++;
}
}
/* Are any arguments required
* but not provided?
*/
if(ArgsRequired && !Counted)
{
Packet . Results[0] = RC_ERROR;
Packet . Results[1] = ERROR_REQUIRED_ARG_MISSING;
}
else
{
struct ExclusionInfo *Exclusion = ExclusionTable[CommandIndex];
/* Any mutually-exclusive arguments? */
if(Exclusion)
{
BYTE ArgsOkay = TRUE;
i = 0;
/* Look for arguments to
* exclude each other.
*/
while(ArgsOkay && Exclusion[i] . A != -1)
{
if(Array[Exclusion[i] . A] && Array[Exclusion[i] . B])
ArgsOkay = FALSE;
else
i++;
}
/* All arguments correct? */
if(ArgsOkay)
Processed = InvokeRexxCommand(&Packet);
else
{
Packet . Results[0] = RC_ERROR;
Packet . Results[1] = ERROR_TOO_MANY_ARGS;
}
}
else
Processed = InvokeRexxCommand(&Packet);
}
/* Free allocated parser data. */
if(!Processed)
FreeArgs(Args);
}
else
{
LONG Error = IoErr();
SetIoErr(Error);
Packet . Results[0] = RC_ERROR;
Packet . Results[1] = IoErr();
}
/* Free parser data. */
if(!Processed)
FreeDosObject(DOS_RDARGS,Args);
}
else
{
Packet . Results[0] = RC_ERROR;
Packet . Results[1] = ERROR_NO_FREE_STORE;
}
/* Free temporary buffer. */
if(!Processed)
FreeVecPooled(Array);
}
else
{
Packet . Results[0] = RC_ERROR;
Packet . Results[1] = ERROR_NO_FREE_STORE;
}
}
else
{
Packet . Array = NULL;
Packet . Args = NULL;
Processed = InvokeRexxCommand(&Packet);
}
if(!Processed)
{
if(Packet . Results[0] && Packet . Results[1])
LastRexxError = Packet . Results[1];
ReplyRexxCommand(RexxMsg,Packet . Results[0],Packet . Results[1]);
}
return(TRUE);
}
}
return(FALSE);
}
/* RexxPktCleanup(struct RexxPkt *Packet,STRPTR Result):
*
* Free the memory allocated for a message packet.
*/
VOID __regargs
RexxPktCleanup(struct RexxPkt *Packet,STRPTR Result)
{
if(Packet -> Args)
{
FreeArgs(Packet -> Args);
FreeDosObject(DOS_RDARGS,Packet -> Args);
}
if(Packet -> Array)
FreeVecPooled(Packet -> Array);
if(Packet -> Results[0])
{
/* Store error code. */
if(Packet -> Results[1])
{
UBYTE Buffer[10];
SPrintf(Buffer,"%ld",LastRexxError = Packet -> Results[1]);
if(Packet -> RexxMsg)
SetRexxVar(Packet -> RexxMsg,"TERM.LASTERROR",Buffer,strlen(Buffer));
}
ReplyRexxCommand(Packet -> RexxMsg,Packet -> Results[0],Packet -> Results[1]);
if(Result)
DeleteArgstring(Result);
}
else
{
if(Result)
{
if(Packet -> RexxMsg)
{
if(Packet -> RexxMsg -> rm_Action & RXFF_RESULT)
ReplyRexxCommand(Packet -> RexxMsg,0,(LONG)Result);
else
{
DeleteArgstring(Result);
ReplyRexxCommand(Packet -> RexxMsg,0,0);
}
}
else
DeleteArgstring(Result);
}
else
ReplyRexxCommand(Packet -> RexxMsg,0,0);
}
}
/* RexxServer(VOID):
*
* Asynchronous ARexx host server.
*/
VOID __saveds
RexxServer(VOID)
{
/* Create the public host port. */
if(RexxPort = CreateMsgPort())
{
struct RexxMsg *RexxMsg;
ULONG SignalSet;
BYTE Done = FALSE;
InitSemaphore(&RexxLaunchSemaphore);
RexxPort -> mp_Node . ln_Name = RexxPortName;
RexxPort -> mp_Node . ln_Pri = 1;
/* Make it a public port. */
AddPort(RexxPort);
/* Signal our father that we're running. */
Signal(ThisProcess,SIG_HANDSHAKE);
/* Go into loop and wait for input. */
do
{
SignalSet = Wait(SIG_KILL | PORTMASK(RexxPort));
/* Are we to quit? */
if(SignalSet & SIG_KILL)
Done = TRUE;
/* This is probably a Rexx command. */
if(SignalSet & PORTMASK(RexxPort))
{
/* Pick up all the messages. */
while(RexxMsg = (struct RexxMsg *)GetMsg(RexxPort))
{
/* This is probably the reply to some
* synchronous function invocation.
*/
if(RexxMsg -> rm_Node . mn_Node . ln_Type == NT_REPLYMSG)
FreeVecPooled(RexxMsg);
else
{
/* At first try to run the
* command asynchronously.
* If this turns out to be
* somewhat `impossible' pass
* it to the `term' main process
* or - if in batch mode - try
* to deal with the message
* on our own.
*/
if(!ParseRexxCommand(RexxMsg))
{
UBYTE Buffer[10];
SPrintf(Buffer,"%ld",LastRexxError = TERMERROR_UNKNOWN_COMMAND);
SetRexxVar(RexxMsg,"TERM.LASTERROR",Buffer,strlen(Buffer));
ReplyRexxCommand(RexxMsg,RC_ERROR,TERMERROR_UNKNOWN_COMMAND);
}
}
}
}
}
while(!Done);
Done = FALSE;
/* Process remaining messages. */
do
{
while(RexxMsg = (struct RexxMsg *)GetMsg(RexxPort))
{
if(RexxMsg -> rm_Node . mn_Node . ln_Type == NT_REPLYMSG)
FreeVecPooled(RexxMsg);
else
ReplyRexxCommand(RexxMsg,-1,0);
}
ObtainSemaphore(&RexxLaunchSemaphore);
if(!RexxLaunchCount)
{
Done = TRUE;
ReleaseSemaphore(&RexxLaunchSemaphore);
}
else
{
ReleaseSemaphore(&RexxLaunchSemaphore);
WaitPort(RexxPort);
}
}
while(!Done);
DeleteMsgPort(RexxPort);
RexxPort = NULL;
}
Forbid();
RexxProcess = NULL;
Signal(ThisProcess,SIG_HANDSHAKE);
}
/* HandleRexx():
*
* Tiny & simple subroutine to read and examine all
* messages coming in to be processed synchronously
* by the `term' main process.
*/
BYTE
HandleRexx()
{
struct RexxPkt *Packet;
/* Obtain the message packet. */
if(Packet = (struct RexxPkt *)GetMsg(TermRexxPort))
{
STRPTR Result;
InRexx = TRUE;
UpdateRequired = TransferUpdateRequired = FALSE;
/* Execute the command. */
Result = (*Packet -> CommandInfo -> Routine)(Packet);
/* Free the packet data. */
RexxPktCleanup(Packet,Result);
/* Update the configuration if necessary. */
if(UpdateRequired)
ConfigSetup();
/* Update the XPR options if necessary. */
if(TransferUpdateRequired)
{
if(ProtocolSetup(TRUE))
SaveProtocolOpts();
}
/* Return the message packet. */
ReplyMsg((struct Message *)Packet);
InRexx = FALSE;
return(TRUE);
}
else
return(FALSE);
}